Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(datetime): scroll to newly selected date when value changes #27806

Merged
merged 50 commits into from
Aug 23, 2023

Conversation

averyjohnston
Copy link
Contributor

@averyjohnston averyjohnston commented Jul 14, 2023

Issue number: Resolves #26391


What is the current behavior?

When updating the value programmatically on an ion-datetime after it has already been created:

  • With grid style: The selected date visually updates, but the calendar does not scroll to the newly selected month.
  • With wheel style: The selected date does not visually update, i.e. the wheels do not move to show the newly selected date.

What is the new behavior?

  • Grid style datetimes now scroll to the selected date using the same animation as when clicking the next/prev month buttons.
    • This animation mirrors the behavior in both MUI and native iOS. See the design doc for more information and screen recordings.
    • The animation will not occur if the month/year did not change, or when the datetime is hidden.
  • Wheel style datetimes now visually update to the selected date. No animation occurs, also mirroring native.
  • The parseDate util has also had its type signatures updated to account for returning undefined when the date string is improperly formatted. This was missed when the util was refactored to support multiple date selection.

Does this introduce a breaking change?

  • Yes
  • No

Other information

@stackblitz
Copy link

stackblitz bot commented Jul 14, 2023

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@github-actions github-actions bot added the package: core @ionic/core package label Jul 14, 2023
amandaesmith3 added 2 commits July 18, 2023 14:13
Base automatically changed from feature-7.2 to main July 19, 2023 18:24
@averyjohnston averyjohnston changed the base branch from main to feature-7.3 July 19, 2023 19:01
Copy link
Contributor

@sean-perkins sean-perkins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still in progress of manually testing. Dropping some early suggestions for changes.

core/src/components/datetime/datetime.tsx Outdated Show resolved Hide resolved
core/src/components/datetime/datetime.tsx Outdated Show resolved Hide resolved
core/src/components/datetime/datetime.tsx Outdated Show resolved Hide resolved
core/src/components/datetime/datetime.tsx Show resolved Hide resolved
* Animate smoothly to the forced month. This will also update
* workingParts and correct the surrounding months for us.
*/
const targetMonthIsEarlier = isBefore(targetValue, workingParts);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Threading:

My understanding of the original issue is that asynchronously setting the datetime on load does not update the view. So if the datetime is going to be set either on load or shortly after load, will users even see this scrolling animation? For example, if a datetime in a modal has its value set as the modal opens, the scrolling would either happen on screen or as the modal transitions in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liamdebeasi Before I get too deep in bug fixes here, I wanted to check whether you still had any concerns with moving forward with the animation. I can understand wanting to avoid making datetime even more complex, and deciding to scrap the animation part would make fixing things up here easier, but there are a few reasons why I still feel we should go through with it:

  1. The animation matches native behavior, as mentioned above.
  2. The datetime won't always be hidden when the value is updated async. While that will definitely be our recommendation (see docs(datetime): add best practices for setting value async ionic-docs#3053), we should avoid glitchy-looking behavior when it isn't the dev's desired pattern. For example, an app could have a dropdown with appointments, and the datetime's value updates to reflect which one you've selected.
  3. The animation is something we already decided on in the design doc, and I would rather commit to that than constantly be rethinking our decisions. This isn't a case where we missed something that dramatically changes the scope; we already recognized that the animation will be difficult, and decided to proceed anyway.

Copy link
Contributor

@liamdebeasi liamdebeasi Jul 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we shouldn't omit the animation just because it is challenging. But I'd also like us to keep in mind that the primary objective is to update the UI, with the animation being a secondary goal. This behavior is similar to #23560 where it is closer to the spec, but it's not critical functionality.

I'm not advocating for removing this, but I do want to make sure we are being cautious. If you recall the old IntersectionObserver implementation in datetime, that consumed a lot of our time before we eventually abandoned that approach in favor of a scroll listener.

Comment on lines -47 to -58

// Open month/year picker
await monthYearButton.click();
await page.waitForChanges();

// Select October 2021
// The year will automatically switch to 2021 when selecting 10
await monthColumn.locator('.picker-item[data-value="10"]').click();
await ionChange.next();

// Close month/year picker
await monthYearButton.click();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These parts aren't needed anymore because changing the value already jumps to the new month.

Copy link
Contributor

@liamdebeasi liamdebeasi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work so far! I found one edge case, though the rest of this is working well.

const didChangeMonth = month !== workingParts.month || year !== workingParts.year;
const bodyIsVisible = el.classList.contains('datetime-ready');
const { isGridStyle, showMonthAndYear } = this;
if (isGridStyle && didChangeMonth && bodyIsVisible && !showMonthAndYear) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you set datetime to a time it still scrolls to another month and then abruptly resets to the selected month.

Example:

<ion-datetime value="2022-02-22T16:30:00"></ion-datetime>

<script>
setTimeout(() => {
  datetime.value = '16:30';
}, 2000);
</script>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed the wonky scrolling in fbf2f9c. The datetime now errors out if you do this, but it looks like this case (setting the value to just a time when the presentation is something other than just time) was never supported; I'm able to trigger the same error on main after messing with it a bit. (Screencast below.) I'm thinking it would be good to add a warning for this improper usage in a separate ticket. Thoughts?

2023-08-08.11-12-18.mp4

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -206,6 +206,10 @@ export class DatetimeButton implements ComponentInterface {
*/
const parsedDatetimes = parseDate(parsedValues.length > 0 ? parsedValues : [getToday()]);

if (!parsedDatetimes) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsure if this is a bug, but if I open the month/year picker as the view datetime begins to animate, the animation gets cancelled and the view never updates to the new value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually seeing it update; maybe I'm just not doing it quickly enough? (Screencast below.) Even if there is a specific timing that borks it, though, I'm not too worried as long as the highlighted date is correct once you do scroll to it. Seems like a small edge case that could be addressed separately.

2023-08-16.14-18-57.mp4

Copy link
Contributor

@liamdebeasi liamdebeasi Aug 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I had outdated code as I can no longer repro the issue I mentioned. However, another bug exists:

Switching to the month/year picker as the animation starts seems to break date selection altogether.

datetime-break.mov

Tested on Chrome 116. I added the following code to datetime/test/display/index.html to get the datetime to update async:

setTimeout(() => {
  datetime.value = '2023-10-23T16:30'
}, 2000);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm able to trigger that on main as well, using the next/prev month buttons. The animation goes through the same methods, so it's the same bug. Thoughts on addressing it separately?

2023-08-18.14-17-38.mp4

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that works for me 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liamdebeasi
Copy link
Contributor

Also thoughts on getting a dev build and getting the community to test?

@averyjohnston
Copy link
Contributor Author

Also thoughts on getting a dev build and getting the community to test?

Dev build posted in the original issue 👍

Copy link
Contributor

@liamdebeasi liamdebeasi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

Let's do a couple things before merging:

  1. Rebase this off feature-7.4 since we want to get this into a feature release.
  2. Wait a couple more days to give devs time to provide feedback re: the dev build. If there's no response by Wednesday I think it's fine to merge. (That way we give them a full week to test)

@averyjohnston averyjohnston changed the base branch from feature-7.3 to feature-7.4 August 21, 2023 14:50
@averyjohnston
Copy link
Contributor Author

I'm waiting on @sean-perkins's review anyway 👀 Definitely think this is worth getting an extra pair of eyes on.

core/src/components/datetime/datetime.tsx Outdated Show resolved Hide resolved
@playaz87
Copy link

Any ETA on when this fix will be released? This bug is currently blocking us from releasing an app.

@liamdebeasi
Copy link
Contributor

As noted in #26391 (comment), this fix will be available in an upcoming minor release of Ionic.

@m1nka
Copy link

m1nka commented Dec 13, 2023

Was this feature ever released? We are experiencing the same problem. Thank you!

@m1nka
Copy link

m1nka commented Dec 13, 2023

Ok, I found a workaround using these instructions. Using @ViewChild('mydatepicker') mydatepicker: IonDateTime; and the this.mydatepicker.reset(); works fine.

I think it would make a lot of sense to reset automatically in case popover/modal is closed / reopened.

@liamdebeasi
Copy link
Contributor

Was this feature ever released? We are experiencing the same problem. Thank you!

This feature was released in Ionic 7.4.0: https://ionic.io/blog/announcing-ionic-7-4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: core @ionic/core package
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants